(********************************************************************) (* DRIVExx *) (* *) (* Version 4.0 *) (* *) (* Copyright (C) 1991-1993 by FeerKnott Computing *) (* *) (* Portions Copyright (C) 1992 by PDG Software *) (* *) (* 3922 Englewood Drive *) (* Champaign, IL 61821 *) (* *) (* (217) 355-8145 (voice) *) (* (217) 355-9661 (modem) *) (* CIS [71160,1045] *) (* *) (* ALL RIGHTS RESERVED *) (********************************************************************) (********************************************************************) (* Written by: Charles B. Little, Ph.D. *) (* Version: 4.00 *) (* Revision Date: 22 January 1993 *) (* Language: Turbo Pascal v7 *) (********************************************************************) I. INTRODUCTION: DRIVExx is a collection of tools, written in Turbo Pascal v7 (v6 TPU available on request), for dealing with block devices in a DOS environment. To the best of our knowledge, no such tools exist in any "professional" programming toolboxes, in any programming language. The tools available here will allow any Pascal programmer who uses disk I/O to gain that extra measure of control over his or her application. At the very least they will have the ability to prevent access of a phantom drive so their nice user interface won't get overwritten by non-interceptable DOS messages like "Insert diskette for drive B: and ..." No pretense is made that DRIVExx is flawless and can't be confused by a determined user who knows all the SUBST, JOIN and ASSIGN tricks, but it seems to work for the things most programmers need. And just about everything you'd want your applications to know about drives is available WITHOUT ACCESSING THEM! The only exceptions to hitting drives are functions GETDPB and DiskWasChanged: GETDPB will hit the disk to read its boot sector, BUT ONLY IF YOU TELL IT TO; and DiskWasChanged will use a BIOS function that spins the disk ONLY if the drive supports changeline detection. And even in these two cases, NO unrecoverable error will result if the functions are executed on a removable drive that doesn't have a disk in it. Much of the required information is available only through undocumented DOS functions and data structures. Wherever a documented function will return the same information, however, the undocumented function is still used as a redundancy check. Indeed, the source code for DRIVExx is probably at least 50% longer than need be due to extensive interlocking redundancy checking. Most of the features of DRIVExx are demonstrated in the demo program DRVDEMO.PAS. The major exceptions are functions ReadDiskSectors and WriteDiskSectors, and function MakeDriveActive, whose description below should make clear why it is impractical to include it in DRVDEMO. DRIVExx is currently available only for TP7, but a TP6 format TPU is available on request. We made the decision to use BASM for all assembler modules to eliminate the need to distribute OBJ files. This means that all you need to use DRIVExx is DRIVEXX.TPU. Consideration will be given to releasing a TP5 version, or even porting to C - if enough users express a desire. II. CONDITIONS: DRIVExx is not free. IT IS SHAREWARE AND IT IS COPYRIGHTED. If you use it you should pay for it -- that's how shareware works. However, you only pay the registration fee. Absolutely no royalties are expected or will be sought if you use it in any commercial program. It comes with the usual caveats (spelled out in the REGISTRATION/ORDER FORM) about suitability, limits of liability, etc. The registration fee is $10. Fees for DRIVExx should be accompanied by a completed REGISTRATION/ORDER FORM, found in the file REGISTER.TXT. A non-disclosure agreement with a major vendor will make it impossible to release the ENTIRE source code as is. A working, compilable version - EXCLUDING the small amount of code covered by the NDA - may be made available. If so, we will tell you where to find the "forbidden" information yourself in a book called "PC Interrupts"; it will still be up to you to write the code. Fees and distribution agreements for source code have not yet been established. Since DRIVExx has not been tested on every conceivable platform and under every flavor of DOS out there, special consideration (i.e., fee waiver or free upgrades) will be given to any user who reports bugs or anomalous behavior, and can suggest a fix. IN OTHER WORDS, BE A BETA TESTER AND GET DRIVExx FREE FOREVER! You may distribute DRIVExx freely as long as all 7 files in the original ZIP file are distributed. Those files are: DRIVExx.TXT size = 39389, date = 1/22/93, time = 4:00am (This file) REGISTER.TXT size = 1944, date = 1/22/93, time = 4:00am (Product registration form) DRIVExx.TPU size = 22160, date = 1/22/93, time = 4:00am DRVDEMO.PAS size = 6349, date = 1/22/93, time = 4:00am (Demo program source code - must have DRIVExx.TPU and DRVDEMO.INC to recompile) DRVDEMO.INC size = 5882, date = 1/22/93, time = 4:00am DRVDEMO.EXE size = 32224, date = 1/22/93, time = 4:00am (Ready to run demo program) NTRFACE.TXT size = 10827, date = 1/22/93, time = 4:00am (Actual INTERFACE section from DRIVExx.PAS) See section VIII for details on product support. III. REQUIREMENTS: DOS versions supported: MS-DOS or PC-DOS 3.0 to 5.0; DR DOS 5 or 6. Hardware supported: IBM or IBM-compatible PC, XT, AT, or PS/2. IV. ACKNOWLEDGEMENTS: MS-DOS and SMARTDRV are trademarks of the Microsoft Corporation DR DOS is a trademark of Digital Research, Inc. PC Tools Deluxe is a trademark of Central Point Software NCACHE is a trademark of Symantec Corporation Stacker is a trademark of Stac Electronics NetWare is a trademark of Novell Any PRODUCT NAME used in this document, but not mentioned above, is likely to be a registered trademark of the company that makes the product. There. DRIVExx is based on information found in the following monographs: The MS-DOS Encyclopedia, R. Duncan, ed., Microsoft Press, 1988 MS-DOS Programmer's Reference, Microsoft Press, 1991 Advanced MS-DOS Programming, R. Duncan, Microsoft Press, 1988 Undocumented DOS, Schulman, et. al., eds., 1990 DOS Programmer's Reference, 3rd ed, Dettmann & Johnson, eds., 1992 PC Interrupts, Brown and Kyle, Addison-Wesley, 1991 System BIOS for ..., Phoenix Technologies, Addison-Wesley, 1989 The Programmer's PC Sourcebook, T. Hogan, Microsoft Press, 1991 V. VERSION NOTES: This version of DRIVExx contains the expected code refinements and bug fixes for previous versions, but it also is missing some features of previous versions that we thought were pretty useful. The function "DriveIsDeviceDriven" is the main casualty in DRIVExx version 4, thanks to the release of SmartDrv version 4. This little Microsoft monster makes it impossible (as far as we know) to walk the device driver chain and match up drives with device drivers and thereby distinguish BIOS-driven devices from installed devices. Thus, any feature (eg, DriveIsSwapped that dealt with swapped Stacker volumes) that relied on our ability to match up drives with device drivers has been eliminated from this version of DRIVExx. We hope to be able to return them in a future release. Two other significant changes: we added a function to return the Novell Netware drive type (GetNetwareDriveType), and we changed the criteria for classifying a drive as "normal". The latter was necessary because a NONDOS or "non-IBM format" (indicated by bit 13 in the device driver attribute word) isn't necessarily abnormal! An example is a hard disk partition on a big disk created by third party utilities under DOS 3.2 or before -- when multiple partitions weren't supported directly. VI. DESCRIPTION OF TYPES AND GLOBAL VARIABLES: Two variable types are defined in the INTERFACE section of DRIVExx. "FakeDPB" is so named because it does not conform to the real DPB structure as defined under any single version of DOS. It nevertheless contains most useful information found in the actual DPB after DOS 3 as well as information from the BPB (if the disk's boot sector was read). The other variable type, SectorArray, is as big as the largest possible (we think) sector size in DOS systems. Types: SectorArray = array[0..1023] of byte; FakeDPB = record {start of BPB in boot record} bytespersex : word; {BPB & DPB} sexperclust : byte; {BPB & DPB} FATstart : word; {BPB & DPB} numFATS : byte; {BPB & DPB} RootdirEnts : word; {BPB & DPB} placeholder : word; {ignore this} mediabyte : byte; {BPB & DPB} sexperFAT : word; {BPB & DPB} SexperTrack : word; {BPB ONLY} NumHeads : word; {BPB ONLY} HiddenSex : longint; {BPB ONLY} TotSexonDisk: longint; {BPB ONLY} {end of standard BPB - 25 bytes} RootdirSex : word; {calculated} ROOTstart : word; {DPB} FirstDataSec : word; {DPB} TotClusts : word; {calculated} TotDataClusts: word; {DPB} Tracks : word; {calculated} Cylinders : word; {calculated} Size : longint; {calculated} accessflag : byte; {DPB} ddunitnum : byte; {DPB} DPBDataValid : boolean; {calculated} end; Global Variables: DOSVER : real The currently running DOS version, expressed as a real number. This information is critical to the proper operation of DRIVExx, since many internal DOS data structures vary from one DOS version to another. You should be aware that some DOS versions do not return a value to this function equal to the product's version number. For example, under MS DOS version 5 this function will return DOSVER = 5.00, but under DR DOS version 6 it will return DOSVER = 3.31! These *known* situations with non-MS versions are dealt with, but full compatibility is assured ONLY under MS-DOS or IBM's PC-DOS. Of course, DRIVExx can see through MS DOS 5's SETVER to get the *real* DOS version. DRDOS : boolean DRIVExx uses an undocumented (but DR-approved) function call to determine SPECIFICALLY whether DR DOS is running. This is important because DR DOS 5 is really a clone of MS DOS 3.3, with some internal data structures modified to accommodate volumes larger than 32M. Thus, programs running under DR DOS 5 can't count on internal (undocumented) data structures to be the same as in any SINGLE version of MS DOS. We also know that ASSIGN and SUBST are not reported the way they are in MS DOS, and suspect that other situations of "aliased" drives may be ambiguously reported under this OS. Therefore, when running under DR DOS we recommend calling the generic DriveIsAliased function and not bothering to try to distinguish between SUBST, ASSIGN, JOIN, NETWORK and IFS (installable file system). See function "DriveIsAliased" in section V below. DevDrvrChainValid : boolean During execution of UpdateDrives, the device driver chain is traced, all block devices in it are found, and their driver addresses are stored in a temporary table. These addresses are then checked against the addresses for these drives contained in each drive's DPB. But some software, notably Norton's NCACHE, will change the addresses reported in the DPBs so they no longer match what was found in the (unchanged) device driver chain. SMARTDRV version 4 (shipped with Windows 3.1) plays similar games with the device driver chain. This makes it impossible to match up drives with device drivers unless program-specific remedies are used. A partial fix for NCACHE was implemented in DRIVExx version 2.00, and a complete rewrite of these functions occurred in DRIVExx version 3.00. However, no such fix has been found for SMARTDRV 4. Therefore, all the functions that depend on finding and matching device driver addresses were removed in DRIVExx version 3.18 after SMARTDRV 4 appeared, so this variable has little significance beyond telling you whether the device driver chain or the DPB has been molested since bootup! NCACHELoaded : boolean {3.00} NCACHE's unusual mode of operation (described immediately above) caused some unexpected problems in the development of DRIVExx; it's conceivable it could also cause other, unforeseen problems with programs that USE DRIVExx, or with ANY program that depends on information about device driver addresses. Since (at one time) we HAD to determine unambiguously whether NCACHE is installed, we simply made this information available with this variable. Works for all versions of NCACHE. StackerLoaded : boolean {3.00} As with NCACHE, we had to determine unambiguously whether Stacker is installed, even though we no longer use this information. We just made the information available. Works for all versions of Stacker. NetWareLoaded : boolean {3.00} Tested only with NetWare version 3.11, but SHOULD be valid for all versions. Distinguishing network drives from local drives under any other networking software should work, since only Novell's products are known (by us, anyway) to bypass the Current Directory Structure and therefore require special treatment apart from DOS's own documented function calls. DriveError : longint A global error code that is the sum of all error codes returned during execution of UpdateDrives. A value of zero means no errors were detected. Only three errors will cause *immediate* exit from UpdateDrives: Error 00001 - wrong DOS version (or OS/2), Error 00002 - not enough memory to create the variable DRIVES^, and Error 00004 - failure to find the address of DOS's List-of-Lists. Because these errors make it impossible to continue processing UpdateDrives, any one of them will result in all booleans being set to false and all strings being set to null. Less serious errors arise mostly as a result of redundancy checking on undocumented DOS functions and data structures, thus execution may continue and multiple errors can be reported. It would then be up to the programmer or user to determine how to proceed. In general it would be unwise to allow a program to proceed if DriveError were non-zero. The procedure ShowDriveError in DRVDEMO.INC will interpret the individual error codes summed in DriveError. This procedure only shows a brief description of the error; REGISTERED USERS WILL RECEIVE A DETAILED DESCRIPTION OF THESE ERRORS, HOW THEY ARISE, AND WHICH DOS FUNCTION CALLS ARE INVOLVED. ANY NON-ZERO DRIVEERROR SHOULD BE REPORTED TO FeerKnott IMMEDIATELY! NumLogicalDrives : byte A short explanation of this variable is that NumLogicalDrives is simply the length of the string AllLogicalDrives, described below. InternalFloppies : byte The number of BIOS-driven floppy drives, deduced from the equipment list word at $0040:$0010. PhysicalFixed : byte The number of actual physical hard drives installed. NumBlockDevs : byte The number of block devices, most accurately described as the number of Drive Parameter Blocks (DPBs) set up during the processing of the CONFIG.SYS file. This is NOT ALWAYS the same as NumLogicalDrives since a logical drive can be "created" using SUBST or JOIN but won't necessarily have a DPB associated with it. Every block device also has a device driver associated with it, whose address can be found in the drive's DPB. MachineID : byte Contains the IBM machine type. AllLogicaldrives : string[32] Logical drives are those associated with real drives, virtual drives, phantom drives (including phantom drives created with DRIVER.SYS), and "aliased" drives created by SUBST or ASSIGN. For example, a two floppy system with a hard disk partitioned into C: and D: and a RAMdisk set up as E: would have 5 logical drives, A: thru E:, and AllLogicalDrives would be the string 'ABCDE'. Having the statement LASTDRIVE=Y in your CONFIG.SYS file and executing SUBST P: C:\DOS would give you 6 logical drives, A: thru E: AND P:, and thus AllLogicalDrives would have the value 'ABCDEP'. Note that P: is a "logical" drive, so NumLogicalDrives is 6 (A: thru E:, and P:), but it does NOT have a DPB associated with it so NumBlockDevs is still 5 (A: thru E: only). Length of this variable was expanded to 32 to accommodate NetWare's six extra "driveletter" characters following 'Z' in the ASCII table. BootableDrives : string[32] This is not very meaningful now that Smartdrv 4 has caused us to abandon our method of walking the device driver chain and finding the "BIOS-driven" drives. Now this string is just a list of ANY drives whose unit number in the device driver is equal to, or less than, 3. We're still working on a foolproof way of identifying which PHYSICAL drives attached to a system may be used to boot the system! Floppies, Hards : string[32] Strings of uppercase driveletters representing the drive types indicated. Only "normal" drives will be reported in these strings, i.e., phantom, aliased, network and IFS drives will be excluded. Thus, AllLogicalDrives may be 'ABC' for a one-floppy, one-hard disk system, but Floppies will just be 'A' since the phantom B: drive will be excluded. Length of these variables was expanded to 32 to accommodate NetWare's six extra "driveletter" characters following 'Z' in the ASCII table. ProcessorType : integer As with the BIOS date, the processor type must be determined and used internally, so we made the information available. The only possible values this variable can take are: 0: unknown 1: 8088/8086 2: 80286 3: 80386 -3: 80386SX 4: 80486 or 80486SX BiosDateString : string[8] The date of the system BIOS, in a non-zero-padded format: mm/dd/yy. Example 3/3/89 (not 03/03/89). VII. DESCRIPTION OF PROCEDURES AND FUNCTIONS: This section describes all procedures and functions declared in the INTERFACE of unit DRIVExx. All functions below that require a character argument will accept either uppercase or lowercase driveletters; characters other than letters of the alphabet will ALWAYS cause boolean functions to return FALSE since each of these functions first calls DrivExists, which of course will return FALSE in such cases. Much of the information here is duplicated in the file NTRFACE.TXT, which is the actual INTERFACE section of DRIVExx. PROCEDURE UpdateDrives Creates or updates the DRIVES^ array. All information in this array is accessible ONLY through the functions described below. DRIVES^ is a "dynamic" array allocated on the heap and consists of one element for each valid drive (a total of NumLogicalDrives elements). Each element in this array requires 148 bytes of heap space. Because the dynamic array technique requires range checking to be OFF, it's especially important not to use an invalid drive letter as an array index, as this would send your program into outer space. Thus, programmers should not have direct access to DRIVES^. This is easily accomplished by keeping it in the IMPLEMENTATION section and doing all necessary range checking within the INTERFACE functions! UpdateDrives is called in the unit initialization, and need not be called directly unless your program shells out to DOS and gives your user an opportunity to do something like access a phantom drive, or create a SUBSTed or JOINed drive. UpdateDrives should be called upon return to your main program to guard against such a situation. FUNCTION DrivExists(drv:char) : boolean Self explanatory. Returns FALSE if the drive doesn't exist. If you type DIR Q: at the DOS prompt and get the message "invalid drive specification", you'll also get FALSE with DrivExists(Q). Conversely, if you don't get "invalid drive specification" then DrivExists will return TRUE. Simple. But of course there's an exception: JOINed drives appear as invalid to DOS, but DRIVExx will still list them. Here's why: suppose you have a real floppy drive A:, but JOIN it to a subdirectory on C: with the command JOIN A: C:\PUKED. You CANNOT now access A: with DOS commands like DIR or CHKDSK; attempting to do so will get you the "invalid drive specification" message. But DOS INT 25h and INT 26h can still do absolute reads and writes to a disk in floppy drive A:! Thus A: still exists for the purposes of DRIVExx. FUNCTION DriveisNormal(drv:char) : boolean This function will return FALSE only if a drive is phantom, aliased, network or IFS. It was simply expedient, for many applications, to DEFINE these types of drives as non-normal. Note that NO size or type information is to be trusted for a non-normal drive. The demo program DRVDEMO illustrates what information is and isn't expected to be valid for non-normal drives. FUNCTION DriveisNONDOS(drv:char) : boolean If a drive's device driver attribute word has bit 13 set, it is technically "NON-IBM format" (NONDOS). NONDOS drives are somewhat rare in our experience, but in one common instance they are dangerous: if you use a PC running IBM AS/400 or System38 emulation, you might have virtual drives created for "PC-Support". These are NONDOS drives. Just trying to access such a drive is dangerous, and trying to run DOS's CHKDSK on one will usually get you a "Memory allocation error. System halted" message. While there's not much we can do to teach IBM to write decent block device drivers for PCs, DRIVExx should make their lousy code easier to live with by avoiding it altogether. Other (benign) examples of NONDOS drives are most hard disk partitions created with third party utilities before DOS 3.3 introduced multiple 32M partitions. They may have bit 13 set, but otherwise they appear to applications as perfectly normal. FUNCTION DriveisRemovable(drv:char) : boolean Self explanatory. Again, we have yet to see it incorrectly classify a drive. The TYPE of removable drive can be found with function RemovableDriveType described below. FUNCTION RemovableDrivetype(drv:char) : byte This uses a variety of methods, including analysis of DPB data in memory, to classify drives. Drive type codes are our own, and DO NOT necessarily correspond to drive type codes returned by DOS function calls (see function PhysicalType below). Returns: 0 : type can't be determined (no error) or drive MAY NOT be removable. 1 : 5.25" 360K 2 : 5.25" 1.2M 3 : 3.5" 720K 4 : 3.5" 1.44M 5 : 3.5" 2.88M {not tested in version 3.00 or later} 6 : TAPE {not tested in version 3.00 or later} 7 : Bernoulli {not tested in version 3.00 or later} $FF : invalid drive specified FUNCTION PhysicalType(drv:char) : byte; This is simply an implementation of IOCTL function calls, and returns EXACTLY the drive type code returned by DOS for ANY drive, not just removables. Returns: 0 : 320K/360K 1 : 1.2 M 2 : 720K 3 : 8-inch, single-density 4 : 8-inch, double-density 5 : hard disk 6 : Tape 7 : 1.44 M (only for DOS 3.3+) 8 : Optical drive? 9 : 2.88 M (only for DOS 5.0+) 10 : other? $FF : abnormal or invalid drive specified } FUNCTION DriveisPhantom(drv:char) : boolean This function is somewhat problematic for DOS versions PRIOR to 3.2, in that "phantomness" in these environments has to be decided primarily based on the value of the byte at $0000:$0504. In one- floppy systems this byte is 0 if the single floppy was most recently accessed as A:, or 1 if it was most recently accessed as B:. However, some otherwise well-behaved programs such as PC Tools Deluxe version 6 WILL change the value at $0504 to $FF in certain situations, rendering this phantom-finding method ineffective. Phantom-finding has been safe and straightforward since DOS 3.2, so only well-behaved and documented functions are used when running under these newer DOS versions. PROCEDURE MakeDriveActive(drv:char) Whenever a phantom drive exists -- whether it's drive B: in a one-floppy system, or one created by DRIVER.SYS -- this procedure will make it active so you don't see the obnoxious "Insert diskette for drive B: and ... " message when you try to access it. This message is NOT interceptable; the only way to avoid it is to avoid trying to access a phantom drive. This procedure does that, AND ALSO CALLS UpdateDrives WHEN IT'S FINISHED!! FUNCTION DriveMappedTo(drv:char) : char If drv is a removable drive and is currently classified as phantom, this function will return the uppercase driveletter of the physical drive to which the phantom is currently mapped. If ANY drive is ASSIGNed, removable or not, this will tell you what drive letter it's assigned to. Unlike JOIN and SUBST, the ASSIGN function does not affect the "current directory" reported in the CDS structure, so it's not as simple to determine drive mapping for ASSIGNed drives. FUNCTION DriveisSubsted(drv:char) : boolean FUNCTION DriveisJoined(drv:char) : boolean FUNCTION DriveisAssigned(drv:char) : boolean (see "DriveMappedTo" above) FUNCTION DriveisNetwork(drv:char) : boolean FUNCTION DriveisIFS(drv:char) : boolean FUNCTION DriveisAliased(drv:char) : boolean (ALIASED = JOINed or SUBSTed or ASSIGNed) The last function in this group, DriveIsAliased, is a shortcut that returns true if a drive is SUBSTed, JOINed, or ASSIGNed. All the others are fairly self-explanatory. These functions have been tested extensively for SUBSTed, JOINed and ASSIGNed drives, but not for NETWORK or IFS drives. User input would be appreciated! If one of these functions returns TRUE, there is little RELIABLE information that can be obtained for it. Under DR DOS, only DriveIsAliased should be called, since the other "aliased" functions may not operate as expected. We KNOW this to be the case for ASSIGN and SUBST, but have not checked it out for NETWORK and IFS drives. FUNCTION GetNetwareDriveType(drv:char) : byte; This is a concession to a user who wanted to be able to figure out how his NetWare drives were mapped. The return values follow the Novell documentation: 0 : drive is not mapped 1 : permanent network drive 2 : temporary network drive 3, 128 : drive exists locally 129 : local drive used as permanent network drive 130 : local drive used as temporary network drive FUNCTION DriveisHard(drv:char) : boolean FUNCTION DriveisRAMDisk(drv:char) : boolean FUNCTION DriveisOtherfixed(drv:char) : boolean These are the only categories of non-removable drives; the functions are also self explanatory. We have yet to see a non-removable drive that couldn't be classified as either hard or RAM disk, but function DriveisOtherfixed is included to take care of this possibility. We use a very common criterion to classify a drive as a RAM disk: if the DPB of a non-removable drive says there is only ONE copy of the FAT, it's called a RAM disk. In addition, we look for specific bits to be set in the device's attribute word. (SuperStore drives that ordinarily would look like hard disks are sometimes incorrectly classified as RAM disks because they only have ONE FAT copy.) FUNCTION ChangeLineSupported(drv:char) : boolean This should return true ONLY for removable drives, and then only if the device driver for the drive says it supports change line detection. FUNCTION DiskWasChanged(drv:char) : boolean This function hits the disk only if there's support for changeline detection. It always returns TRUE (disk WAS changed!) if there's no disk in the drive. FUNCTION DiskSyze(drv:char) : longint Returns 0 : usually only for a drive (removable or not) that hasn't been accessed since bootup, and so has no valid DPB data to use > 0 : disk size IN BYTES; if the disk is REMOVABLE, DiskSyze returns the size of last disk accessed in the drive FUNCTION CurrentDir(drv:char) : pathstr Returns the currently logged directory for the specified drive as a complete path, including driveletter, colon and final backslash, all in uppercase letters. If the drive doesn't exist, or if the drive is a Netware drive, a null string is returned. This information is obtained from the Current Directory Structure and should be correct for all local drives - except when some versions of the NetWare Shell are running! In these cases the CDS for EACH AND EVERY drive - even local drives - reports that the ROOT directory is the current directory, even when it isn't! We don't yet know of a NetWare function that will obtain the CORRECT current directory information without hitting the disk, so some caution is required in using this function when Netware is running. We should emphasize that NOT ALL NETWARE versions do this! For JOINed and SUBSTed drives, CurrentDir will tell you which drive/subdirectory is really active. This is not true for ASSIGNed drives. See Function DriveMappedTo above (and program DRVDEMO) for more info on ASSIGNed drives. FUNCTION DefaultDrive : char Identifies the current default drive as an uppercase letter. No error checking is done on the returned value; we know it works in every case when NetWare isn't loaded, though. FUNCTION GETDPB(drv:char; var drvinfo:fakeDPB; hit:boolean) : word Puts useful drive data from DPB (and BPB) into variable 'DRVINFO'. If HIT is TRUE, the function will hit the disk to update the DPB data in memory. Otherwise it will return data already in memory, usually for the last disk that was accessed in the drive. GETDPB returns FALSE if problems were encountered (drv is an invalid drive, no disk in drive when HIT is set to TRUE, etc.) and all fields of DRVINFO will be zeroed out. Please note that some information in the FakeDPB structure DRVINFO, such as sectors-per-track, is located in the disk's boot record and not in the DPB in memory. Therefore, these fields will be filled in ONLY if this function is called with Hit = TRUE since the boot sector must be read from the disk. Only drives that are *NORMAL* are allowed to be hit; aliased drives, phantom drives, network drives, etc, will not be hit. GETDPB(drv,F,FALSE) returns 0 : no error, F contains only DPB data $F7F7 : drive doesn't exist (no other return values possible) GETDPB(drv,F,TRUE) returns 0 : no error, F contains DPB data, BPB data and derived data $F4F4 : can't allocate buffer to receive boot sector $F5F5 : DPB says bytes per sector > 1024 $F6F6 : drive is not normal (could be phantom or aliased) $F7F7 : drive doesn't exist $FF00 : DOS Fnc $32 (GetDPB) failed else : error code generated by INT $25 (Absolute Read): Hi byte = BIOS error code Lo byte = DOS error code (eg, BIOS error 128 means drive not ready or no disk in drive, BIOS error 2,6 or 12 could mean disk isn't formatted). All fields of F will be zeroed out. GetDPB will work for ANY drive that exists if Hit = FALSE, and will return data from the DPB in memory. That's because the DPB doesn't know or care whether a drive is SUBSTed or phantom or otherwise NOT NORMAL. If a non-normal drive is passed to GetDPB with Hit = TRUE, the function will IMMEDIATELY return $F6F6. We only allow the disk to be read when we're sure the drive letter passed corresponds to the physical drive that will be hit. Since we use DOS absolute disk reads (INT $25), and not BIOS reads (INT $13, Fnc $02) to read the boot sector, DOS will redirect our absolute disk read if the drive is aliased. For example, suppose drive A: has been SUBSTed with the command SUBST A: C:\TEMP If we allowed the drive to be accessed unconditionally, the command GetDPB('A',F,TRUE) would end up reading the boot sector of drive C: in this case, and the data in F would have nothing to do with drive A:. THIS IS WHY WE DON'T ALLOW A DISK TO BE ACCESSED WITH THIS FUNCTION UNLESS IT'S A NORMAL DRIVE (not phantom, not network, not JOINed, etc.). FUNCTION ReadDiskSectors(drv:char;frst:longint;num:word;var Buf):word This function implements DOS INT $25 for absolute disk reads. The entire routines are in BASM so no OBJ files are required. Error codes are $F7F7 if drive doesn't exist, or whatever error code is generated by DOS INT $25 (BIOS error code in high byte, DOS error code in low byte, just like GetBOOT below and GetDPB above). "num" is the number of sectors to be read, starting at sector "frst", and Buf is the variable to receive the data. While we've NEVER seen it written in ANY reference ANYWHERE, we know that INT $25 will not read more that 64K at a time. Assuming the standard 512-byte sector, this means "num" can be no more than 128 sectors. However, INT $25 will not *always* return an error when trying to read more than 128 sectors (or 64K) at a time! On one machine we've seen this function work without returning an error until "num" exceeded 160 sectors (82K); of course, anything over 128 just got wrapped around to the beginning of Buf. FUNCTION WriteDiskSectors(drv:char;frst:longint;num:word;var Buf):word Implements DOS INT $26. See ReadDiskSectors above. FUNCTION ShowBIOSDriveNum(drv:char) : byte The purpose of this function is to find out which physical drive corresponds to a given logical drive. Whatever PHYSICAL disk you would hit with a function like ReadDiskSectors(drv, 0, 1, buf) is what this returns. It does not try to figure out DOS redirection commands like JOIN or ASSIGN. If DRV is not a physical disk (eg, RAMDISK) or if DRV is a phantom, the function returns $FF. Based on interception of DOS INT $25 call and determination of the drivenumber passed to INT $13 Fnc $02. NO DISKS ARE HIT; THE INT $25 CALL IS ALWAYS INTERCEPTED AND CONTROL RETURNED WITHOUT ACTUAL DISK ACCESS. IMPORTANT: DOS INT $25 ignores JOIN, but DOES NOT ignore ASSIGN or SUBST! EXAMPLES: SUBST A: C:\ Y := ShowBIOSDriveNum('A'); Y returns 128 (first hard disk), not 0 (first floppy) ASSIGN A: C: Y := ShowBIOSDriveNum('A'); Y returns 128 (first hard disk), not 0 (first floppy) BUT... JOIN A: C:\PUKED Y := ShowBIOSDriveNum('A'); Y returns 0! (BIOS drive number for A:, not C:) FUNCTION GETBOOT(drv:char; var S:SectorArray) : word Reads boot sector and puts it directly into array S. THE ONLY CHECKING DONE BY THIS PROCEDURE IS ON PHANTOM DRIVES. ALL OTHERS WILL BE HIT BY INT $25 AND ANY REDIRECTION BY SUBST OR ASSIGN WILL AFFECT THE OUTCOME! returns 0 : no error, S contains boot sector as read $F4F4 : can't allocate buffer to receive boot sector $F5F5 : DPB for drive says bytes per sector > 1024 $F6F6 : drive is phantom $F7F7 : drive doesn't exist else : error code generated by INT $25 (Absolute Read): failed attempt to read boot sector - DOS errorcode in the low byte and BIOS error code in the high byte (eg, BIOS error 128 means no disk in drive). Though it's not common, it's possible for a disk's sector size to be greater than 512 bytes. As far as we know, 1024 is the MAXIMUM sector size under any existing version of DOS, so to avoid overwriting memory that's how big we made SectorArray. All unused portions of S will be zeroed out. VIII. PRODUCT SUPPORT: Product support (voice) is available at (217) 355-8145 after 7pm Weekdays (Eastern), 10am to 4pm Saturdays, or by U.S. Mail (as often as the mail runs). We expect to have BBS support available soon. General questions, bug reports and/or suggestions for improvement are always welcome from ANYONE, whether registered or not. No collect calls can be accepted, but we can take a phone number and return your call. ----------------end-of-author's-documentation--------------- Software Library Information: This disk copy provided as a service of Public (software) Library We are not the authors of this program, nor are we associated with the author in any way other than as a distributor of the program in accordance with the author's terms of distribution. Please direct shareware payments and specific questions about this program to the author of the program, whose name appears elsewhere in this documentation. If you have trouble getting in touch with the author, we will do whatever we can to help you with your questions. All programs have been tested and do run. To report problems, please use the form that is in the file PROBLEM.DOC on many of our disks or in other written for- mat with screen printouts, if possible. PsL cannot debug pro- programs over the telephone, though we can answer questions. Disks in the PsL are updated monthly, so if you did not get this disk directly from the PsL, you should be aware that the files in this set may no longer be the current versions. Also, if you got this disk from another vendor and are having prob- lems, be aware that some files may have become corrupted or lost by that vendor. Get a current, working disk from PsL. For a copy of the latest monthly software library newsletter and a list of the 4,000+ disks in the library, call or write Public (software) Library P.O.Box 35705 - F Houston, TX 77235-5705 1-800-2424-PSL MC/Visa/AmEx/Discover Outside of U.S. or in Texas or for general information, Call 1-713-524-6394